package global

import (
	"encoding/json"
	"errors"
	"src/zeus/common"
	"src/zeus/dbservice"
	"src/zeus/dbservice/redislib"

	"src/zeus/logger"
)

const (
	globalVariantTypeString      = 1
	globalVariantTypeInt         = 2
	globalVariantTypeEntityProxy = 3
	globalVariantTypeIntSlice    = 4
)

type globalInfo struct {
	variantType uint8
	val         interface{}
}

func newGlobalInfo(varType uint8, val interface{}) *globalInfo {
	return &globalInfo{
		variantType: varType,
		val:         val,
	}
}

// Global 支持分布式结构的全局数据结构
type Global struct {
	variants map[string]*globalInfo
}

var globalInst *Global

// GetGlobalInst 获取到全局变量指针
func GetGlobalInst() *Global {

	if globalInst == nil {
		globalInst = &Global{}
		globalInst.init()
	}

	return globalInst
}

func (g *Global) init() {
	// iserver.GetSrvInst().AddListener(g.getGlobalRefreshEvtName(), g, "GlobalVariantChanged")
	g.refreshGlobal()
}

func (g *Global) getGlobalRefreshEvtName() string {
	return "Event_GlobalRefresh"
}

func (g *Global) getGlobalKeyPrefix() string {
	return "Global_Variants:"
}

func (g *Global) getGlobalKeysKey() string {
	return "Global_Keys"
}

func (g *Global) refreshGlobal() {
	return
	// //从Redis的Global表中获取全局变量
	// var values []string
	// var err error
	// redislib.RedisUsing(dbservice.GetSessionRedis(), func(c *redislib.RedisHandleModel) {
	// 	values, err = c.SMembers(c.Ctx, g.getGlobalKeysKey()).Result()
	// 	// values, err = redis.Values(c.Do("SMEMBERS", g.getGlobalKeysKey()))
	// })
	// if err != nil {
	// 	logger.Error("获取全局变量异常", err)
	// 	return
	// }

	// g.variants = make(map[string]*globalInfo)

	// for i := 0; i < len(values); i++ {
	// 	globalName := values[i]
	// 	// globalName, _ := redis.String(values[i], nil)
	// 	variantType, val, err := g.getGlobalFromDB(globalName)

	// 	if err != nil {
	// 		logger.Error("全局变量刷新异常", globalName, err)
	// 		continue
	// 	}

	// 	g.variants[globalName] = newGlobalInfo(variantType, val)
	// }

}

func (g *Global) getGlobalFromDB(globalName string) (variantType uint8, val interface{}, err error) {
	keyName := g.getGlobalKeyPrefix() + globalName
	var vars map[string]string
	redislib.RedisUsing(dbservice.GetSessionRedis(), func(c *redislib.RedisHandleModel) {
		vars, err = c.HGetAll(c.Ctx, keyName).Result()
		// values, err = redis.Values(c.Do("HGETALL", keyName))
	})

	if err != nil {
		return
	}

	// vars := make(map[string]interface{})
	// for i := 0; i < len(values); i += 2 {
	// 	str, _ := redis.String(values[i], nil)
	// 	vars[str] = values[i+1]
	// }

	_, ok := vars["variantType"]
	if !ok {
		err = errors.New("全局变量表异常")
		return
	}

	err = nil

	// varType, _ := common.NewString(vars["variantType"], nil)
	// variantType = uint8(varType)
	variantType = uint8(common.NewString(vars["variantType"]).ToIntV())
	switch variantType {
	case globalVariantTypeString:
		val, _ = vars["stringVal"] //redis.String(vars["stringVal"], nil)
	case globalVariantTypeInt:
		val, _ = common.NewString(vars["intVal"]).ToInt()
	case globalVariantTypeEntityProxy:
		e := make(map[string]uint64)
		e["entityID"], _ = common.NewString(vars["entityID"]).ToUint64()
		e["srvID"], _ = common.NewString(vars["srvID"]).ToUint64()
		e["spaceID"], _ = common.NewString(vars["spaceID"]).ToUint64()
		val = e
	case globalVariantTypeIntSlice:
		e := make(map[string][]int)
		var data []byte
		data = []byte(vars["intSliceVal"]) //redis.Bytes(vars["intSliceVal"], nil)
		if err != nil {
			return
		}

		var ret []int
		err = json.Unmarshal(data, &ret)
		if err != nil {
			return
		}
		e["intSliceVal"] = ret

		data = []byte(vars["intSliceVal2"])
		if err != nil {
			return
		}

		var ret2 []int
		err = json.Unmarshal(data, &ret2)
		if err != nil {
			return
		}
		e["intSliceVal2"] = ret2
		val = e
	default:
		err = errors.New("错误的全局变量类型")
		return
	}

	return
}

// // GlobalVariantChanged 当全局变量发生改变时收到通知
// func (g *Global) GlobalVariantChanged(args string) {
// 	keyName := g.getGlobalKeyPrefix() + string(args)
// 	var isKeyExisted int64
// 	var err error
// 	redislib.RedisUsing(dbservice.GetSessionRedis(), func(c *redislib.RedisHandleModel) {
// 		isKeyExisted, err = c.Exists(c.Ctx, keyName).Result()
// 		// isKeyExisted, err = redis.Bool(c.Do("EXISTS", keyName))
// 	})
// 	if err != nil {
// 		logger.Error(err)
// 		return
// 	}

// 	if isKeyExisted == 1 {

// 		variantType, val, err := g.getGlobalFromDB(args)

// 		if err != nil {
// 			logger.Error(err)
// 			return
// 		}

// 		g.variants[args] = newGlobalInfo(variantType, val)
// 	} else {
// 		delete(g.variants, args)
// 	}

// }

// // RemoveGlobal 移除全局变量
// func (g *Global) RemoveGlobal(globalName string) {

// 	if _, ok := g.variants[globalName]; !ok {
// 		return
// 	}
// 	redislib.RedisUsing(dbservice.GetSessionRedis(), func(c *redislib.RedisHandleModel) {
// 		c.Del(c.Ctx, g.getGlobalKeyPrefix()+globalName)
// 		c.SRem(c.Ctx, g.getGlobalKeysKey(), globalName)
// 		// c.Do("DEL", g.getGlobalKeyPrefix()+globalName)
// 		// c.Do("SREM", g.getGlobalKeysKey(), globalName)
// 	})

// 	// iserver.GetSrvInst().FireEvent(g.getGlobalRefreshEvtName(), globalName)
// }

// // SetGlobalStr 设置全局变量字符串
// func (g *Global) SetGlobalStr(globalName string, val string) {

// 	redislib.RedisUsing(dbservice.GetSessionRedis(), func(c *redislib.RedisHandleModel) {
// 		var hashArgs []interface{}
// 		// hashArgs = append(hashArgs, g.getGlobalKeyPrefix()+globalName)
// 		hashArgs = append(hashArgs, "variantType")
// 		hashArgs = append(hashArgs, globalVariantTypeString)
// 		hashArgs = append(hashArgs, "stringVal")
// 		hashArgs = append(hashArgs, val)
// 		// c.Do("HMSET", hashArgs...)
// 		c.HMSet(c.Ctx, g.getGlobalKeyPrefix()+globalName, hashArgs...)
// 		// c.Do("HSET", g.getGlobalKeyPrefix()+globalName, "variantType", globalVariantTypeString)
// 		// c.Do("HSET", g.getGlobalKeyPrefix()+globalName, "stringVal", val)

// 		// c.Do("SADD", g.getGlobalKeysKey(), globalName)
// 		c.SAdd(c.Ctx, g.getGlobalKeysKey(), globalName)
// 	})

// 	// iserver.GetSrvInst().FireEvent(g.getGlobalRefreshEvtName(), globalName)
// }

// SetGlobalInt 设置全局变量Int
func (g *Global) SetGlobalInt(globalName string, val int) {

	redislib.RedisUsing(dbservice.GetSessionRedis(), func(c *redislib.RedisHandleModel) {
		var hashArgs []interface{}
		// hashArgs = append(hashArgs, g.getGlobalKeyPrefix()+globalName)
		hashArgs = append(hashArgs, "variantType")
		hashArgs = append(hashArgs, globalVariantTypeInt)
		hashArgs = append(hashArgs, "intVal")
		hashArgs = append(hashArgs, val)
		// c.Do("HMSET", hashArgs...)
		c.HMSet(c.Ctx, g.getGlobalKeyPrefix()+globalName, hashArgs...)

		// c.Do("HSET", g.getGlobalKeyPrefix()+globalName, "variantType", globalVariantTypeInt)
		// c.Do("HSET", g.getGlobalKeyPrefix()+globalName, "intVal", val)

		// c.Do("SADD", g.getGlobalKeysKey(), globalName)
		c.SAdd(c.Ctx, g.getGlobalKeysKey(), globalName)
	})

	// iserver.GetSrvInst().FireEvent(g.getGlobalRefreshEvtName(), globalName)
}

// SetGlobalEntityProxy 设置全局实体代理对象
func (g *Global) SetGlobalEntityProxy(globalName string, entityID, srvID, spaceID uint64) {

	redislib.RedisUsing(dbservice.GetSessionRedis(), func(c *redislib.RedisHandleModel) {
		var hashArgs []interface{}
		// hashArgs = append(hashArgs, g.getGlobalKeyPrefix()+globalName)
		hashArgs = append(hashArgs, "variantType")
		hashArgs = append(hashArgs, globalVariantTypeEntityProxy)
		hashArgs = append(hashArgs, "entityID")
		hashArgs = append(hashArgs, entityID)
		hashArgs = append(hashArgs, "srvID")
		hashArgs = append(hashArgs, srvID)
		hashArgs = append(hashArgs, "spaceID")
		hashArgs = append(hashArgs, spaceID)

		// c.Do("HMSET", hashArgs...)
		c.HMSet(c.Ctx, g.getGlobalKeyPrefix()+globalName, hashArgs...)
		// c.Do("SADD", g.getGlobalKeysKey(), globalName)
		c.SAdd(c.Ctx, g.getGlobalKeysKey(), globalName)
	})

	// iserver.GetSrvInst().FireEvent(g.getGlobalRefreshEvtName(), globalName)
}

// SetGlobalIntSlice 设置int slice
func (g *Global) SetGlobalIntSlice(globalName string, val []int, val2 []int) {
	data, err := json.Marshal(val)
	if err != nil {
		logger.Error(err)
		return
	}
	data2, err2 := json.Marshal(val2)
	if err2 != nil {
		logger.Error(err2)
		return
	}

	redislib.RedisUsing(dbservice.GetSessionRedis(), func(c *redislib.RedisHandleModel) {
		var hashArgs []interface{}
		// hashArgs = append(hashArgs, g.getGlobalKeyPrefix()+globalName)
		hashArgs = append(hashArgs, "variantType")
		hashArgs = append(hashArgs, globalVariantTypeIntSlice)
		hashArgs = append(hashArgs, "intSliceVal")
		hashArgs = append(hashArgs, data)
		hashArgs = append(hashArgs, "intSliceVal2")
		hashArgs = append(hashArgs, data2)

		// c.Do("HMSET", hashArgs...)
		c.HMSet(c.Ctx, g.getGlobalKeyPrefix()+globalName, hashArgs...)
		// c.Do("SADD", g.getGlobalKeysKey(), globalName)
		c.SAdd(c.Ctx, g.getGlobalKeysKey(), globalName)
	})
	// iserver.GetSrvInst().FireEvent(g.getGlobalRefreshEvtName(), globalName)
}

// // GetGlobalStr 获取全局变量字符串
// func (g *Global) GetGlobalStr(globalName string) string {

// 	info, ok := g.variants[globalName]
// 	if !ok {
// 		return ""
// 	}

// 	if info.variantType != globalVariantTypeString {
// 		logger.Warn("全局变量类型错误")
// 		return ""
// 	}

// 	return info.val.(string)
// }

// // GetGlobalInt 获取全局变量Int
// func (g *Global) GetGlobalInt(globalName string) int {

// 	info, ok := g.variants[globalName]
// 	if !ok {
// 		return 0
// 	}

// 	if info.variantType != globalVariantTypeInt {
// 		logger.Warn("全局变量类型错误")
// 		return 0
// 	}

// 	return info.val.(int)
// }

// GetGlobalEntityProxy 获取全局变量Entity代理
func (g *Global) GetGlobalEntityProxy(globalName string) (uint64, uint64, uint64) {
	info, ok := g.variants[globalName]
	if !ok {
		return 0, 0, 0
	}

	if info.variantType != globalVariantTypeEntityProxy {
		logger.Warn("全局变量类型错误")
		return 0, 0, 0
	}

	e := info.val.(map[string]uint64)
	return e["entityID"], e["srvID"], e["spaceID"]
}

// GetGlobalIntSlice 获取int slice
func (g *Global) GetGlobalIntSlice(globalName string) ([]int, []int) {
	info, ok := g.variants[globalName]
	if !ok {
		return nil, nil
	}

	if info.variantType != globalVariantTypeIntSlice {
		logger.Warn("全局变量类型错误 ", globalName, " 类型 ", info.variantType)
		return nil, nil
	}
	e := info.val.(map[string][]int)
	return e["intSliceVal"], e["intSliceVal2"]
}
